package io.gitee.zhangbinhub.admin.service

import io.gitee.zhangbinhub.acp.boot.exceptions.WebException
import io.gitee.zhangbinhub.admin.base.OauthBaseService
import io.gitee.zhangbinhub.admin.constant.RoleCode
import io.gitee.zhangbinhub.admin.entity.Role
import io.gitee.zhangbinhub.admin.entity.User
import io.gitee.zhangbinhub.admin.po.RolePo
import io.gitee.zhangbinhub.admin.repo.MenuRepository
import io.gitee.zhangbinhub.admin.repo.ModuleFuncRepository
import io.gitee.zhangbinhub.admin.repo.RoleRepository
import io.gitee.zhangbinhub.admin.repo.UserRepository
import io.gitee.zhangbinhub.admin.vo.RoleVo
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

/**
 * @since JDK 11
 */
@Service
@Transactional(transactionManager = "transactionManagerPrimary", readOnly = true)
class RoleService @Autowired
constructor(
    userRepository: UserRepository,
    private val roleRepository: RoleRepository,
    private val menuRepository: MenuRepository,
    private val moduleFuncRepository: ModuleFuncRepository
) : OauthBaseService(userRepository) {

    @Throws(WebException::class)
    fun getRoleList(): MutableList<Role> = roleRepository.findAllByOrderBySortAsc()

    @Throws(WebException::class)
    fun getRoleListByAppId(loginNo: String, appId: String): List<Role> {
        val user = getUserInfoByLoginNo(loginNo) ?: throw WebException("无法获取当前用户信息")
        return if (isSuper(user)) {
            roleRepository.findByAppIdOrderBySortAsc(appId)
        } else {
            roleRepository.findByAppIdAndLevelsGreaterThanOrderBySortAsc(appId, getRoleMinLevel(appId, user))
        }
    }

    @Throws(WebException::class)
    private fun doSave(userInfo: User, role: Role, rolePo: RolePo): Role =
        userRepository.findAllById(rolePo.userIds).toMutableSet().let { userSetPo ->
            if (validateModifyUserSet(userInfo, role.userSet, userSetPo)) {
                roleRepository.save(
                    role.copy(
                        name = rolePo.name!!,
                        code = rolePo.code!!,
                        sort = rolePo.sort,
                        levels = rolePo.levels,
                        type = rolePo.type,
                        userSet = userSetPo,
                        menuSet = menuRepository.findAllById(rolePo.menuIds).toMutableSet(),
                        moduleFuncSet = moduleFuncRepository.findAllById(rolePo.moduleFuncIds).toMutableSet()
                    )
                )
            } else {
                throw WebException("不合法的操作，不允许修改更高级别的用户列表！")
            }
        }

    @Transactional
    @Throws(WebException::class)
    fun doCreate(loginNo: String, rolePo: RolePo): Role =
        getUserInfoByLoginNo(loginNo)?.let { userInfo ->
            if (!isSuper(userInfo)) {
                val currLevel = getRoleMinLevel(rolePo.appId!!, userInfo)
                if (currLevel >= rolePo.levels) {
                    throw WebException("没有权限做此操作，角色级别必须大于 $currLevel")
                }
            }
            if (rolePo.code == RoleCode.SUPER) {
                throw WebException("不允许创建超级管理员")
            }
            doSave(userInfo, Role(appId = rolePo.appId!!), rolePo)
        } ?: throw WebException("无法获取当前用户信息")

    @Transactional
    @Throws(WebException::class)
    fun doDelete(loginNo: String, idList: MutableList<String>) {
        val user = getUserInfoByLoginNo(loginNo) ?: throw WebException("无法获取当前用户信息")
        if (!isSuper(user)) {
            val roleMinLevel = getRoleMinLevel(user)
            val roleList = roleRepository.findAllById(idList)
            roleList.forEach {
                if (!roleMinLevel.containsKey(it.appId) || roleMinLevel.getValue(it.appId) >= it.levels) {
                    throw WebException("没有权限做此操作")
                }
            }
        }
        roleRepository.deleteByIdIn(idList)
    }

    @Transactional
    @Throws(WebException::class)
    fun doUpdate(loginNo: String, rolePo: RolePo): Role =
        getUserInfoByLoginNo(loginNo)?.let { userInfo ->
            val role = roleRepository.getReferenceById(rolePo.id!!)
            if (!isSuper(userInfo)) {
                val currLevel = getRoleMinLevel(role.appId, userInfo)
                if (currLevel > 0 && currLevel >= rolePo.levels) {
                    throw WebException("没有权限做此操作，角色级别必须大于 $currLevel")
                }
                if (currLevel > 0 && currLevel >= role.levels) {
                    throw WebException("没有权限做此操作，请联系系统管理员")
                }
            } else {
                if (rolePo.code != role.code && role.code == RoleCode.SUPER) {
                    throw WebException("超级管理员编码不允许修改")
                }
                if (rolePo.levels != role.levels && role.levels <= 0) {
                    throw WebException("超级管理员级别不允许修改")
                }
                if (rolePo.levels != role.levels && rolePo.levels <= 0) {
                    throw WebException("不允许修改为超级管理员级别[" + rolePo.levels + "]")
                }
            }
            doSave(userInfo, role, rolePo)
        } ?: throw WebException("无法获取当前用户信息")

    @Throws(WebException::class)
    fun getRoleInfo(roleId: String): RoleVo =
        roleRepository.getReferenceById(roleId).let { item ->
            RoleVo(
                id = item.id,
                appId = item.appId,
                code = item.code,
                levels = item.levels,
                name = item.name,
                sort = item.sort,
                type = item.type,
                userIds = item.userSet.map { it.id }.toMutableList(),
                menuIds = item.menuSet.map { it.id }.toMutableList(),
                moduleFuncIds = item.moduleFuncSet.map { it.id }.toMutableList()
            )
        }
}
